/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.json;

import com.tencent.tendon.convert.util.CreatorFields;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author nbzhang
 */
@SuppressWarnings("unchecked")
public final class JsonObjectDecoder<T> extends JsonDecoder<T> {

    private JsonDeHandle head;

    private JsonInterceptor<T> interceptor;

    private String[] constructorFields;

    private JsonDeHandle[] constructorHandles;

    private JsonDeHandle[] othermethodHandles;

    private int handleSize;

    JsonObjectDecoder(Class<T> type) {
        super(type);
        this.head = JsonDeHandle.NULL;
        this.handleSize = 0;
    }

    void setJsonDeHandle(JsonDeHandle head) {
        this.head = head;
        this.handleSize = head.size();
        String[] fields = null;
        try {
            CreatorFields cf = creator.getClass().getMethod("create", Object[].class).getAnnotation(CreatorFields.class);
            if (cf != null) fields = cf.value();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (fields != null) {
            this.constructorFields = fields;
            JsonDeHandle handle;
            JsonDeHandle[] handles1 = new JsonDeHandle[fields.length];
            for (int i = 0; i < fields.length; i++) {
                handle = this.head.find(fields[i]);
                if (handle == null) throw new JsonException("not found Handle(" + fields[0] + ") for " + this.creator.getClass().getName() + "(" + this.type + ")");
                handle.index(i);
                handles1[i] = handle;
            }
            this.constructorHandles = handles1;

            List<JsonDeHandle> handles2 = new ArrayList<JsonDeHandle>();
            handle = this.head;
            int index = handles1.length;
            do {
                boolean flag = true;
                for (JsonDeHandle h : handles1) {
                    if (h == handle) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    handle.index(index++);
                    handles2.add(handle);
                }
            } while ((handle = handle.next) != null);
            this.othermethodHandles = handles2.toArray(new JsonDeHandle[handles2.size()]);
            if ((handles1.length + handles2.size()) != this.handleSize) throw new JsonException("error " + this.creator.getClass().getName() + "for Type(" + this.type + ")");
        }
    }

    void setJsonInterceptor(JsonInterceptor<T> interceptor) {
        this.interceptor = interceptor;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName() + "{type:" + this.type + ", simpled:" + simpled + ",\r\n   handles:" + this.head + "}";
    }

    @Override
    public T convertFrom(final JsonReader in) {
        JsonDeHandle handle = head;
        in.checkObject();
        final T result;
        if (this.constructorFields == null) {
            result = this.creator.create();
            if (!this.simpled) in.offer(result);
            while (in.hasNext()) {
                if (handle == null) handle = head;
                JsonDeHandle curr = in.readField(handle);
                in.checkColon();
                if (curr == null) {
                    in.skipValue(); //跳过该属性的值
                } else if (curr == JsonDeHandle.REFER) {
                    if (!this.simpled) in.poll();
                    return (T) JsonReferDecoder.getInstance().convertReferFrom(in);
                } else {
                    handle = curr.next;
                    curr.set(in, result);
                }
            }
            if (!this.simpled) in.poll();
        } else {
            JsonDeHandle[] methodHandles = this.othermethodHandles;
            final int csize = this.constructorHandles.length;
            final int olen = methodHandles.length;
            Object[] constructors = new Object[csize];
            Object[] othermethods = new Object[olen];
            boolean[] otherindexs = new boolean[olen];
            while (in.hasNext()) {
                if (handle == null) handle = head;
                JsonDeHandle curr = in.readField(handle);
                in.checkColon();
                if (curr == null) {
                    in.skipValue(); //跳过该属性的值
                } else if (curr == JsonDeHandle.REFER) {
                    if (!this.simpled) in.poll();
                    return (T) JsonReferDecoder.getInstance().convertReferFrom(in);
                } else {
                    handle = curr.next;
                    int index = curr.index();
                    if (index < csize) {
                        constructors[index] = curr.getValue(in);
                    } else {
                        othermethods[index - csize] = curr.getValue(in);
                        otherindexs[index - csize] = true;
                    }
                }
            }
            result = this.creator.create(constructors);
            for (int i = 0; i < otherindexs.length; i++) {
                if (otherindexs[i]) methodHandles[i].setValue(result, othermethods[i]);
            }
        }
        return interceptor == null ? result : interceptor.postDecode(result);
    }
}
